package com.jilujia.domain.question;

import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.jilujia.domain.question.repository.AnswerRepository;
import com.jilujia.domain.question.repository.QuestionRepository;
import com.jilujia.framework.domain.AbstractPoEntityManager;
import com.jilujia.framework.util.CalculateUtil;
import com.jilujia.web.CacheConstants;

@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class QuestionManager extends AbstractPoEntityManager<Long, Question, QuestionRepository> {

	private static final Logger LOG = LoggerFactory.getLogger(QuestionManager.class);

	@Autowired
	private AnswerRepository answerRepository;

	// TODO viewCount的相关方法应该不应该在manager里面？？？
	@Autowired
	private CacheManager cacheManager;

	@Transactional
	public Question saveQuestion(Question questionVo, Long userId) {
		// 初始化PO
		Question questionPo = new Question();

		// new Question
		Date now = new Date(System.currentTimeMillis());
		questionPo.setCreatedDate(now);
		questionPo.setModifyDate(now);
		questionPo.setUserId(userId);

		// 直接发布

		// 把VO属性copy到PO上
		questionPo.processVo(questionVo);

		// 之前所有的动作都是为了生成完整的PO
		this.setInstance(questionPo);
		this.save();

		return questionPo;
	}

	@Cacheable(value = CacheConstants.QUESTIONS_VIEWCOUNT_CACHENAME, key = "'question_viewcount:'+#questionId")
	public Integer getViewCount(Long questionId) {
		Assert.notNull(questionId, "Required questionId must not be null");

		Integer viewCount = this.getRepository().findQuestionViewCountByQuestion(questionId);
		return viewCount;
	}

	public void addViewCount(Long questionId) {
		Assert.notNull(questionId, "Required instance's id must not be null");

		String key = "question_viewcount:" + questionId;
		Integer viewCount = (Integer) cacheManager.getCache(CacheConstants.QUESTIONS_VIEWCOUNT_CACHENAME).get(key).get();
		viewCount = viewCount + 1;
		cacheManager.getCache(CacheConstants.QUESTIONS_VIEWCOUNT_CACHENAME).put(key, viewCount);

	}

	@Transactional
	@CacheEvict(value = CacheConstants.QUESTIONS_VIEWCOUNT_CACHENAME, key = "'question_viewcount:'+#questionId")
	public void saveViewCount(Long questionId, Integer viewCount) {
		this.getRepository().saveViewCount(questionId, viewCount);

	}

	@Transactional
	public void addAnswerCount() {
		Question question = this.getInstance();
		question.setModifyDate(new Date(System.currentTimeMillis()));
		question.setAnswerCount(question.getAnswerCount() + 1);

		calculatePop();

		this.save();
	}

	@Transactional
	public void changeVoteCount(boolean useful) {
		Question question = this.getInstance();
		question.setModifyDate(new Date(System.currentTimeMillis()));
		if (useful) {
			question.setVoteCount(question.getVoteCount() + 1);
		} else {
			question.setVoteCount(question.getVoteCount() - 1);
		}

		this.calculatePop();
		this.save();
	}

	@Transactional
	public void changeAnswerVoteSum() {
		Question question = this.getInstance();
		// 更新修改时间
		question.setModifyDate(new Date(System.currentTimeMillis()));
		// 计算answer投票总数
		Long answerVoteSum = answerRepository.sumAnswerVoteByQuestionId(question.getId());
		question.setAnswerVoteSum(answerVoteSum);
		// 计算pop
		this.calculatePop();
		this.save();
	}

	@Transactional
	private void calculatePop() {

		Question question = this.getInstance();

		double x = 0;
		if (question.getViewCount() > 0) {
			x = CalculateUtil.multiply(Math.log10(question.getViewCount()), 4);
		}

		LOG.debug("x:{}", x);

		LOG.debug("getVoteCount:{}", question.getVoteCount());
		LOG.debug("getAnswerCount:{}", question.getAnswerCount());

		double y = CalculateUtil.divide(CalculateUtil.multiply(question.getVoteCount(), question.getAnswerCount()), 5);

		LOG.debug("y:{}", y);

		Long z = question.getAnswerVoteSum();

		LOG.debug("z:{}", z);

		double age = CalculateUtil.divide(
				CalculateUtil.substract(new Date().getTime(), question.getCreatedDate().getTime()), 1000);// 除以1000是为了转换成秒

		double lastUpdate = CalculateUtil.divide(
				CalculateUtil.substract(new Date().getTime(), question.getModifyDate().getTime()), 1000);// 除以1000是为了转换成秒

		double w = Math
				.pow(
						CalculateUtil.add(CalculateUtil.add(CalculateUtil.divide(age, 2), CalculateUtil.divide(lastUpdate, 2)), 1),
						1.5);

		LOG.debug("w:{}", w);

		// double pop = CalculateUtil.divide(CalculateUtil.add(CalculateUtil.add(x,
		// y), z), w);
		double pop = (x + y + z) / w;

		LOG.debug("pop:{}", pop);

		question.setPop(pop);
	}
}
